#include "sCRC.h"

uint32_t crc_invert_bits(uint32_t data, uint8_t bits)
{
    uint32_t out = 0;
    #if 0
    uint8_t i;
    for (i = 0; i < bits; i++)
    {
        out |= (data&(1<<i)) ? (1<<(bits-1-i)) : 0;
    }
    #else
    while(bits--)
    {
        out = (out << 1) | (data & 1);
        data >>= 1;
    }
    #endif
    return out;
}

uint32_t crc_calculate(const crc_config_t *cfg, uint32_t crc_init, const void *pdata, uint32_t byteLen)
{
    uint32_t maxBit = 1 << (cfg->width - 1);
    uint8_t *pdata8 = (uint8_t *)pdata;
    uint8_t shift = cfg->width - 8;
    if (cfg->invertInput)
    {
        while (byteLen--)
        {
            crc_init ^= crc_invert_bits((*pdata8++), 8) << (shift);
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//1
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//2
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//3
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//4
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//5
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//6
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//7
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//8
        }
    }
    else
    {
        while (byteLen--)
        {
            crc_init ^= (*pdata8++) << (shift);
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//1
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//2
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//3
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//4
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//5
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//6
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//7
            crc_init = (crc_init&maxBit) ? ((crc_init<<1)^cfg->polynomial) : (crc_init<<1);//8
        }
    }
    crc_init ^= cfg->xorOutput;
    return cfg->invertOutput ? crc_invert_bits(crc_init, cfg->width) : crc_init;
}




/* 常用CRC参数

CRC算法名称        宽度  多项式       初始值       结果异或值    输入反转  输出反转
CRC-4/ITU          4  ,  0x03      , 0x00       , 0x00      ,    1   ,    1
CRC-5/EPC          5  ,  0x09      , 0x09       , 0x00      ,    0   ,    0
CRC-5/ITU          5  ,  0x15      , 0x00       , 0x00      ,    1   ,    1
CRC-5/USB          5  ,  0x05      , 0x1F       , 0x1F      ,    1   ,    1
CRC-6/ITU          6  ,  0x03      , 0x00       , 0x00      ,    1   ,    1
CRC-7/MMC          7  ,  0x09      , 0x00       , 0x00      ,    0   ,    0
CRC-8              8  ,  0x07      , 0x00       , 0x00      ,    0   ,    0
CRC-8/ITU          8  ,  0x07      , 0x00       , 0x55      ,    0   ,    0
CRC-8/ROHC         8  ,  0x07      , 0xFF       , 0x00      ,    1   ,    1
CRC-8/MAXIM        8  ,  0x31      , 0x00       , 0x00      ,    1   ,    1
CRC-16/IBM         16 ,  0x8005    , 0x0000     , 0x0000    ,    1   ,    1
CRC-16/MAXIM       16 ,  0x8005    , 0x0000     , 0xFFFF    ,    1   ,    1
CRC-16/USB         16 ,  0x8005    , 0xFFFF     , 0xFFFF    ,    1   ,    1
CRC-16/MODBUS      16 ,  0x8005    , 0xFFFF     , 0x0000    ,    1   ,    1
CRC-16/CCITT       16 ,  0x1021    , 0x0000     , 0x0000    ,    1   ,    1
CRC-16/CCITT-FALSE 16 ,  0x1021    , 0xFFFF     , 0x0000    ,    0   ,    0
CRC-16/X25         16 ,  0x1021    , 0xFFFF     , 0xFFFF    ,    1   ,    1
CRC-16/XMODEM      16 ,  0x1021    , 0x0000     , 0x0000    ,    0   ,    0
CRC-16/DNP         16 ,  0x3D65    , 0x0000     , 0xFFFF    ,    1   ,    1
CRC-32             32 ,  0x04C11DB7, 0xFFFFFFFF , 0xFFFFFFFF,    1   ,    1
CRC-32/MPEG-2      32 ,  0x04C11DB7, 0xFFFFFFFF , 0x00000000,    0   ,    0
*/

const crc_config_t CRC_CFG_4_ITU          = crc_config_create(4  ,  0x03      , 0x00       , 0x00      ,    1   ,    1);
const crc_config_t CRC_CFG_5_EPC          = crc_config_create(5  ,  0x09      , 0x09       , 0x00      ,    0   ,    0);
const crc_config_t CRC_CFG_5_ITU          = crc_config_create(5  ,  0x15      , 0x00       , 0x00      ,    1   ,    1);
const crc_config_t CRC_CFG_5_USB          = crc_config_create(5  ,  0x05      , 0x1F       , 0x1F      ,    1   ,    1);
const crc_config_t CRC_CFG_6_ITU          = crc_config_create(6  ,  0x03      , 0x00       , 0x00      ,    1   ,    1);
const crc_config_t CRC_CFG_7_MMC          = crc_config_create(7  ,  0x09      , 0x00       , 0x00      ,    0   ,    0);
const crc_config_t CRC_CFG_8              = crc_config_create(8  ,  0x07      , 0x00       , 0x00      ,    0   ,    0);
const crc_config_t CRC_CFG_8_ITU          = crc_config_create(8  ,  0x07      , 0x00       , 0x55      ,    0   ,    0);
const crc_config_t CRC_CFG_8_ROHC         = crc_config_create(8  ,  0x07      , 0xFF       , 0x00      ,    1   ,    1);
const crc_config_t CRC_CFG_8_MAXIM        = crc_config_create(8  ,  0x31      , 0x00       , 0x00      ,    1   ,    1);
const crc_config_t CRC_CFG_16_IBM         = crc_config_create(16 ,  0x8005    , 0x0000     , 0x0000    ,    1   ,    1);
const crc_config_t CRC_CFG_16_MAXIM       = crc_config_create(16 ,  0x8005    , 0x0000     , 0xFFFF    ,    1   ,    1);
const crc_config_t CRC_CFG_16_USB         = crc_config_create(16 ,  0x8005    , 0xFFFF     , 0xFFFF    ,    1   ,    1);
const crc_config_t CRC_CFG_16_MODBUS      = crc_config_create(16 ,  0x8005    , 0xFFFF     , 0x0000    ,    1   ,    1);
const crc_config_t CRC_CFG_16_CCITT       = crc_config_create(16 ,  0x1021    , 0x0000     , 0x0000    ,    1   ,    1);
const crc_config_t CRC_CFG_16_CCITT_FALSE = crc_config_create(16 ,  0x1021    , 0xFFFF     , 0x0000    ,    0   ,    0);
const crc_config_t CRC_CFG_16_X25         = crc_config_create(16 ,  0x1021    , 0xFFFF     , 0xFFFF    ,    1   ,    1);
const crc_config_t CRC_CFG_16_XMODEM      = crc_config_create(16 ,  0x1021    , 0x0000     , 0x0000    ,    0   ,    0);
const crc_config_t CRC_CFG_16_DNP         = crc_config_create(16 ,  0x3D65    , 0x0000     , 0xFFFF    ,    1   ,    1);
const crc_config_t CRC_CFG_32             = crc_config_create(32 ,  0x04C11DB7, 0xFFFFFFFF , 0xFFFFFFFF,    1   ,    1);
const crc_config_t CRC_CFG_32_MPEG2       = crc_config_create(32 ,  0x04C11DB7, 0xFFFFFFFF , 0x00000000,    0   ,    0);




